using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
using System.Collections;
using NovodexWrapper;

namespace marbletrack
{
    class ContactReport : NxUserContactReport
    {
        public void onContactNotify(NxContactPair contactPair, uint events)
        {
            float force = contactPair.sumNormalForce.magnitude();
            //Put sound stuff here
            //the NxContactPairFlag enum can be used to check what event has occured eg.) if (events == (uint)NxContactPairFlag.NX_NOTIFY_ON_START_TOUCH)
            //the actors that can be access by contactPair.Actor0 and contactPair.Actor1 define many physics properties such as linear velocity
            //contactPair.Actor0/1.getGroup() can be called to get the physics group the actor belongs to which is either Ball.PHYSICS_GROUP or TrackPiece.PHYSICS_GROUP at the present time

            if (BallcollidesWithTrack(contactPair) && events == (uint)NxContactPairFlag.NX_NOTIFY_ON_START_TOUCH && force > 2e14)
            {
                Audio.trackHitVol = (float)(force/6e15);
                Audio.PlayTrackHit();
            }

            //if two balls collide (only called on start touch)
            if (contactPair.Actor0.getGroup() == Physics.BALL_PHYSICS_GROUP && contactPair.Actor1.getGroup() == Physics.BALL_PHYSICS_GROUP && events == (uint)NxContactPairFlag.NX_NOTIFY_ON_START_TOUCH)
            {
                Audio.PlayMarbleHit();
            }

            if (BallcollidesWithTrack(contactPair))
            {
                //This is how to get the ball from the actor's UserData property
                Ball ball;
                unsafe
                {
                    if (contactPair.Actor0.getGroup() == Physics.BALL_PHYSICS_GROUP)
                    {
                        BallData *ballData = (BallData*)(contactPair.Actor0.UserData.ToPointer());
                        ball = ballData->GetBall();
                    }
                    else
                    {
                        BallData *ballData = (BallData*)(contactPair.Actor1.UserData.ToPointer());
                        ball = ballData->GetBall();
                    }
                }
                Audio.PlayMarbleRoll();
            }

            //Audio.update();

            //Boosts the ball if it hits an up slope
            if (contactPair.Actor0.getGroup() == Physics.BALL_PHYSICS_GROUP && contactPair.Actor1.getGroup() == Physics.BOOST_PHYSICS_GROUP)
            {
                Boost(contactPair.Actor0, contactPair.Actor1);
            }
            else if (contactPair.Actor1.getGroup() == Physics.BALL_PHYSICS_GROUP && contactPair.Actor0.getGroup() == Physics.BOOST_PHYSICS_GROUP)
            {
                Boost(contactPair.Actor1, contactPair.Actor0);
            }
        }

        private bool BallcollidesWithTrack(NxContactPair contactPair)
        {
            if (((contactPair.Actor0.getGroup() == Physics.TRACKPIECE_PHYSICS_GROUP || contactPair.Actor0.getGroup() == Physics.BOOST_PHYSICS_GROUP) &&
                contactPair.Actor1.getGroup() == Physics.BALL_PHYSICS_GROUP) ||
                (contactPair.Actor0.getGroup() == Physics.BALL_PHYSICS_GROUP &&
                (contactPair.Actor1.getGroup() == Physics.TRACKPIECE_PHYSICS_GROUP || contactPair.Actor1.getGroup() == Physics.BOOST_PHYSICS_GROUP)))
                return true;
            else
                return false;
        }

        //Check which direction the trackPiece is facing and Boost (spin) the ball in that direction
        private void Boost(NxActor ball, NxActor trackPiece)
        {
            if (MathConversion.NxMat33ToMatrix(trackPiece.GlobalOrientation) == TrackPiece.StraightOrientation)
            {
                ball.AngularVelocity += new NxVec3(5, 0, 0);
            }
            else if (MathConversion.NxMat33ToMatrix(trackPiece.GlobalOrientation) == TrackPiece.LeftOrientation)
            {
                ball.AngularVelocity += new NxVec3(0, 0, -5);
            }
            else if (MathConversion.NxMat33ToMatrix(trackPiece.GlobalOrientation) == TrackPiece.RightOrientation)
            {
                ball.AngularVelocity += new NxVec3(0, 0, 5);
            }
            else
            {
                ball.AngularVelocity += new NxVec3(-5, 0, 0);
            }
        }
    }
}
